#ifndef CAMERA_H
#define CAMERA_H

#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

enum CameraMovement
{
    FORWARD,
    BACKWARD,
    LEFT,
    RIGHT
};

class Camera{
    public:
        glm::vec3 position;
        glm::vec3 front;
        glm::vec3 up;
        glm::vec3 right;
        glm::vec3 worldup;
        // 欧拉角
        float yaw;
        float pitch;
        float roll;
        // 相机选项
        float moveSpeed;
        float rotationSpeed;
        float fov;

    Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f),glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float pitch = 0.0f, float yaw = 0.0f, glm::vec3 worldup = glm::vec3(0.0f,1.0f,0.0f)) : front(glm::vec3(0.0f, 0.0f, -1.0f)), moveSpeed(1.0f), rotationSpeed(0.1f), fov(45.0f){
        this->position = position;
        this->up = up;
        this->pitch = pitch;
        this->yaw = yaw;
        this->worldup = worldup;
        UpdateVectors();
    }

    void SetMoveSpeed(float speed){
        moveSpeed = speed;
    }

    void SetRotationSpeed(float speed){
        rotationSpeed = speed;
    }

    glm::mat4 GetViewMat(){
        return glm::lookAt(position, position + front, up);
    }

    void ProcessMovement(CameraMovement direction, float deltaTime){
        float velocity = deltaTime * moveSpeed;
        switch (direction)
        {
        case CameraMovement::FORWARD:
            position += velocity * front;
            break;
        case CameraMovement::BACKWARD:
            position -= velocity * front;
            break;
        case CameraMovement::LEFT:
            position -= velocity * right;
            break;
        case CameraMovement::RIGHT:
            position += velocity * right;
            break;
        default:
            break;
        }
        UpdateVectors();
    }

    void ProcessCameraRotate(float xOffset, float yOffset, bool constrainPitch=true){
        xOffset *= rotationSpeed;
        yOffset *= rotationSpeed;

        yaw += xOffset;
        pitch += yOffset;

        if (constrainPitch){
            if (pitch>89.0f){
                pitch = 89.0f;
            }
            if (pitch < -89.0f)
            {
                pitch = -89.0f;
            }
        }
        UpdateVectors();
    }

    void ProcessMouseScroll(float yOffset){
        fov -= yOffset;
        if (fov < 1.0f)
            fov = 1.0f;
        if (fov > 45.0f)
            fov = 45.0f;
    }

    private:
    void UpdateVectors(){
        front = glm::normalize(glm::vec3(
                                        cos(glm::radians(pitch)) * cos(glm::radians(yaw)),
                                        sin(glm::radians(pitch)),
                                        cos(glm::radians(pitch)) * sin(glm::radians(yaw))
                                    ));
        right = glm::normalize(glm::cross(front, worldup));
        up = glm::normalize(glm::cross(right, front));
    }
};

#endif
